package com.niiwoo.civet.trade.service.local.newRefund.common;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.niiwoo.civet.base.enums.OrderTradeSourceEnum;
import com.niiwoo.civet.trade.dao.entity.*;
import com.niiwoo.civet.trade.service.local.refund.CommonLocalService;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.niiwoo.civet.base.enums.RefundOrderStatusEnum;
import com.niiwoo.civet.trade.dao.entity.RefundWithholdOrder;
import com.niiwoo.civet.trade.dao.mapper.BorrowFlowConfigMapperExt;
import com.niiwoo.civet.trade.dao.mapper.ProjectBorrowerPlanNewMapperExt;
import com.niiwoo.civet.trade.dao.mapper.ProjectBorrowerSummaryMapperExt;
import com.niiwoo.civet.trade.dao.mapper.ProjectMapperExt;
import com.niiwoo.civet.trade.dao.mapper.RefundOrderMapperExt;
import com.niiwoo.civet.trade.dao.mapper.RefundWithholdOrderMapperExt;
import com.niiwoo.civet.trade.dao.mapper.RefundWithholdRequestMapperExt;
import com.niiwoo.civet.trade.dao.mapper.RefundWithholdOrderMapperExt;
import com.niiwoo.civet.trade.dao.mapper.RepaymentGuideMapperExt;
import com.niiwoo.civet.trade.dto.ProjectBorrowerPlanNewDTO;
import com.niiwoo.civet.trade.dto.request.RefundWithholdRequestDTO;
import com.niiwoo.civet.trade.dto.response.myloan.GetWithholdRepaymentResultDTO;
import com.niiwoo.civet.trade.dto.response.myloan.ProjectrePaymentResponseDTO;
import com.niiwoo.civet.trade.dto.response.myloan.QueryRepaymentProjectSummaryDTO;
import com.niiwoo.civet.trade.dto.response.myloan.RefundGuideContentResponseDTO;
import com.niiwoo.civet.trade.dto.response.myloan.UserProjectStatisticResponseDTO;
import com.niiwoo.civet.trade.utils.RepaymentUtil;
import com.niiwoo.civet.user.dto.response.UserCreditInfoDTO;
import com.niiwoo.civet.user.enums.CreditEnum;
import com.niiwoo.civet.user.service.UserCreditDubboService;
import com.niiwoo.tripod.provider.exception.BizException;

import lombok.extern.slf4j.Slf4j;

/**
 * 还款本地服务 
 *
 * @author: kevin.jia
 * @version 1.0.0
 */
@Slf4j
@Service
public class RefundLocalService {
	
	@Autowired
	private ProjectMapperExt projectMapper;
	
	@Autowired
	private ProjectBorrowerPlanNewMapperExt projectBorrowerPlanNewMapper;
	
	@Autowired
	private ProjectBorrowerSummaryMapperExt projectBorrowerSummaryMapper;
	
	@Autowired
	private RepaymentGuideMapperExt repaymentGuideMapper;
	
	@Autowired 
	private BorrowFlowConfigMapperExt borrowFlowConfigMapper;

	@Autowired
	private RefundWithholdRequestMapperExt refundWithholdRequestMapper;

	@Autowired
	private RefundOrderMapperExt refundOrderMapperExt;
	
	@Autowired
	private RefundWithholdOrderMapperExt refundWithholdOrderMapper;

	@Autowired
	private RefundCommonService refundCommonService;
	
	@Reference(version = "1.0.0")
	private UserCreditDubboService userCreditDubboService;

	@Autowired
	protected CommonLocalService commonLocalService;

	/**
	 * 查询还款订单
	 * 
	 * @param projectId
	 * @param orgRequestNo
	 * @return
	 */
	public GetWithholdRepaymentResultDTO getWithholdRepaymentResult(Long projectId, String orgRequestNo) {
		Assert.notNull(projectId, "标的ID不能为空");
		Assert.notNull(orgRequestNo, "机构请求流水号不能为空");

		GetWithholdRepaymentResultDTO getRepaymentResultDTO = new GetWithholdRepaymentResultDTO();
		getRepaymentResultDTO.setProjectId(projectId);
		getRepaymentResultDTO.setOrgRequestNo(orgRequestNo);

		// 查询还款代扣请求订单
		RefundWithholdRequest refundWithholdRequest = refundWithholdRequestMapper.selectByProjectIdAndOrgRequestNo(projectId, orgRequestNo);

		// 代扣还款请求记录
		if (refundWithholdRequest == null) return null;

		// 存在还款请求
		if (Byte.valueOf("3").equals(refundWithholdRequest.getStatus())) {
			getRepaymentResultDTO.setStatus(RefundOrderStatusEnum.HANDLEFAIL.getCode());
			getRepaymentResultDTO.setErrorCode(refundWithholdRequest.getErrorCode());
			getRepaymentResultDTO.setErrorMessage(refundWithholdRequest.getErrorMessage());
		} else if (Byte.valueOf("1").equals(refundWithholdRequest.getStatus())) {
			getRepaymentResultDTO.setStatus(RefundOrderStatusEnum.INITIALIZE.getCode());
		} else {
			// 代扣还款请求记录状态为成功，则标的还款状态默认初始化
			getRepaymentResultDTO.setStatus(RefundOrderStatusEnum.INITIALIZE.getCode());

			// 优化考虑还款订单状态
			RefundOrder refundOrder = refundOrderMapperExt.selectByProjectIdAndOrgRequestNo(projectId, orgRequestNo);
			if (null != refundOrder) {
				getRepaymentResultDTO.setStatus(refundOrder.getStatus());
				getRepaymentResultDTO.setErrorCode(refundOrder.getErrorCode());
				getRepaymentResultDTO.setErrorMessage(refundOrder.getErrorMessage());
			}
			// 还款订单不存在，再考虑代扣订单的状态
			else {
				RefundWithholdOrder refundWithholdOrder = refundWithholdOrderMapper.selectByProjectIdAndOrgRequestNo(projectId, orgRequestNo);
				if (null != refundWithholdOrder && RefundWithholdRequestDTO.WithholdOrderProcessingEnum.FAILURE.getValue().equals(refundWithholdOrder.getStatus())) {
					getRepaymentResultDTO.setStatus(RefundOrderStatusEnum.HANDLEFAIL.getCode());
					getRepaymentResultDTO.setErrorCode(refundWithholdOrder.getErrorCode());
					getRepaymentResultDTO.setErrorMessage(refundWithholdOrder.getErrorMessage());
				} else if (null != refundWithholdOrder && RefundWithholdRequestDTO.WithholdOrderProcessingEnum.FAILURE.getValue().equals(refundWithholdOrder.getRefundStatus())) {
					getRepaymentResultDTO.setStatus(RefundOrderStatusEnum.HANDLEFAIL.getCode());
					getRepaymentResultDTO.setErrorCode(refundWithholdOrder.getErrorCode());
					getRepaymentResultDTO.setErrorMessage(refundWithholdOrder.getErrorMessage());
				}
			}
		}

		return getRepaymentResultDTO;
	}

	/**
	 * 根据标的ID获取还款摘要
	 * 
	 * @param projectId
	 * @return
	 */
	public QueryRepaymentProjectSummaryDTO getRepaymentProjectSummary(Long projectId) {
		Assert.notNull(projectId, "请求ProjectId不能为空");
        ProjectBorrowerSummary projectBorrowerSummary = projectBorrowerSummaryMapper.selectByPrimaryKey(projectId);
        QueryRepaymentProjectSummaryDTO queryRepaymentProjectSummaryDTO = new QueryRepaymentProjectSummaryDTO();
        BeanUtils.copyProperties(projectBorrowerSummary, queryRepaymentProjectSummaryDTO);
        queryRepaymentProjectSummaryDTO.setUserId(projectBorrowerSummary.getBorrowerUserId());
        return queryRepaymentProjectSummaryDTO;
	}
	
	/**
	 * 根据标的ID和用户ID集合获取还款计划
	 * 
	 * @param borrowerUserIdProjectIdDTO
	 * @return
	 */
	public List<ProjectrePaymentResponseDTO> getProjectRepaymentForProjectIdList(List<Map<String, Long>> borrowerUserIdProjectIdDTO) {
		List<ProjectrePaymentResponseDTO> projectrePaymentResponseDTOList = new ArrayList<ProjectrePaymentResponseDTO>();
		borrowerUserIdProjectIdDTO.forEach(biz -> {
			Iterator<Map.Entry<String, Long>> it = biz.entrySet().iterator();
			while (it.hasNext()) {
				Map.Entry<String, Long> entry = it.next();
				List<ProjectBorrowerPlanNewDTO> borrowerPlanNewList = refundCommonService.getProjectBorrowerPlanNewList(entry.getValue(), entry.getKey());
				for (ProjectBorrowerPlanNewDTO projectBorrowerPlanNewDTO : borrowerPlanNewList) {
					projectrePaymentResponseDTOList.add(transformProjectPaymentResponse(projectBorrowerPlanNewDTO));
				}
			}
		});
		return projectrePaymentResponseDTOList;
	}

	/**
	 * 根据标的ID和用户ID获取还款计划
	 * 
	 * @param projectId
	 * @param userId
	 * @return
	 */
    public List<ProjectrePaymentResponseDTO> listRepaymentPlanByProjectIdAndUserId(Long projectId, String userId) {
        List<ProjectBorrowerPlanNewDTO> projectBorrowerPlanNewDTOList = refundCommonService.getProjectBorrowerPlanNewList(projectId, userId);
        List<ProjectrePaymentResponseDTO> projectrePaymentResponseDTOList = new ArrayList<>();
        for (ProjectBorrowerPlanNewDTO projectBorrowerPlanNewDTO : projectBorrowerPlanNewDTOList) {
        	projectrePaymentResponseDTOList.add(transformProjectPaymentResponse(projectBorrowerPlanNewDTO));
        }
        return projectrePaymentResponseDTOList;
    }
    
    /**
     * 还款成功引导
     */
    public RefundGuideContentResponseDTO refundGuideContent(String userId) {
        RefundGuideContentResponseDTO responseDTO = new RefundGuideContentResponseDTO();
        UserCreditInfoDTO infoDTO = userCreditDubboService.getUserCreditInfoByType(userId);
        log.info("查询用户额度信息###infoDTO={}",JSON.toJSONString(infoDTO));
        RepaymentGuide repaymentGuide = repaymentGuideMapper.selectRepaymentActivity();
        log.info("查询还款引导复借配置表###repaymentGuide={}",JSON.toJSONString(repaymentGuide));
        //扩展字段，备用，1还款成功-未获得提额、未获得优惠页面，默认值为1
        BorrowFlowConfig borrowFlowConfig = borrowFlowConfigMapper.selectByType((short) 1);
        log.info("查询借款流程链接配置表###borrowFlowConfig={}",JSON.toJSONString(borrowFlowConfig));
        UserProjectStatisticResponseDTO borrowerCount = projectMapper.selectSuccessAmount(userId);
        log.info("查询用户借款成功次数###borrowerCount={}",borrowerCount.getSuccessCount());
        //复借引导（1、活动上线，根据配置的上线时间； 2、满足条件，授信额度>=X；3、满足条件，成功借款次数>=Y）
        if (repaymentGuide != null && infoDTO != null
                && repaymentGuide.getCreditAmount() != null
                && repaymentGuide.getCreditLoanNum() != null
                && infoDTO.getCreditAmount().compareTo(repaymentGuide.getCreditAmount()) >= 0
                && borrowerCount.getSuccessCount() >= repaymentGuide.getCreditLoanNum()) {
            responseDTO.setIsRepaymentActivity(Byte.valueOf("1")); //是否参加复借活动 0、否，1、是
            responseDTO.setTitle(repaymentGuide.getTitle());
            responseDTO.setImgUrl(repaymentGuide.getImageUrl());
            responseDTO.setAddressUrl(repaymentGuide.getAddress());
        }
        if (infoDTO != null && CreditEnum.NeedUpdateStatus.YES.getType().equals(infoDTO.getNeedUpdate())) {
            //是否要更新额度
            responseDTO.setIsUpdateLimit(CreditEnum.NeedUpdateStatus.YES.getType());
        }
        if(borrowFlowConfig != null && borrowFlowConfig.getIsShow() == 1){  //是否显示 0不显示1 显示
            responseDTO.setTitle(borrowFlowConfig.getTitle());
            responseDTO.setImgUrl(borrowFlowConfig.getImageLink());
            responseDTO.setAddressUrl(borrowFlowConfig.getLink());
        }
        return responseDTO;
    }
    
    
    /**
     * 检查是否可以执行正常还款
     * @param summary
     */
	public void checkRepayment(ProjectBorrowerSummary summary) {
		Project project = projectMapper.selectByPrimaryKey(summary.getProjectId());
		Date maxDate = new DateTime(commonLocalService.getCurrentDate()).plusMonths(1).toDate();
		if (maxDate.after(summary.getRefundDate()) || Byte.valueOf("2").equals(project.getDeadlineUnit())){
			return;
		}
		int currentPeriod = summary.getCurrentPeriod();
		if (summary.getCurrentPeriod() > 1) {
			int totalPeriod = summary.getTotalPeriod();
			throw new BizException("TRD30005", (currentPeriod - 1) + "/" + totalPeriod);
		}

		// 不可提前一个月操作当期还款
		throw new BizException("TRD30004");
	}
	
	/**
	 * 较验当前是否可以执行还款
	 * 
	 * @param projectId
	 */
	public void checkRepaymentByProjectId(Long projectId) {
		ProjectBorrowerSummary summary = projectBorrowerSummaryMapper.selectByPrimaryKey(projectId);
		if (summary == null) {
			throw new BizException("TRD20001");
		}
		this.checkRepayment(summary);
	}
	
	/**
	 * 统计用户当前逾期标的数
	 * 
	 * @param userId
	 * @return
	 */
    public Integer countOverdueProject(String userId){
        return projectMapper.selectOverdueCount(userId);
    }	
    
    /**
     * 统计用户指定逾期日期标的数
     * 
     * @param userId
     * @param exceedDays
     * @return
     */
	public Integer selectOverdueExceedConditionRepayment(String userId, Integer exceedDays) {
		return projectBorrowerPlanNewMapper.selectOverdueExceedConditionRepayment(userId, exceedDays);
	}

	/**
	 * 查询标的指定期数最后一次还款成功的还款来源
	 * @param projectId
	 * @param period
	 * @return
	 */
	public OrderTradeSourceEnum queryLastRefundOrderTradeSourceByProjectIdAndPeriod(Long projectId, Integer period){
		Assert.notNull(projectId, "projectId is null.");
		Assert.notNull(period, "moneyTotal amountType is null.");
		Byte tradeSource = refundOrderMapperExt.queryLastRefundTradeSourceByProjectIdAndPeriod(projectId, period);
		log.info("queryLastRefundOrderTradeSourceByProjectIdAndPeriod projectId:{}, period:{}, tradeSource:{}",projectId, period, tradeSource);
		return OrderTradeSourceEnum.enumOf(tradeSource);
	}

    private ProjectrePaymentResponseDTO transformProjectPaymentResponse(ProjectBorrowerPlanNewDTO projectBorrowerPlanNewDTO) {
		ProjectrePaymentResponseDTO projectrePaymentResponseDTO = new ProjectrePaymentResponseDTO();
		projectrePaymentResponseDTO.setId(projectBorrowerPlanNewDTO.getId());
		projectrePaymentResponseDTO.setProjectId(projectBorrowerPlanNewDTO.getProjectId());
		projectrePaymentResponseDTO.setBorrowerUserId(projectBorrowerPlanNewDTO.getUserId());
		projectrePaymentResponseDTO.setCurrentPeriod(projectBorrowerPlanNewDTO.getPeriod());
		projectrePaymentResponseDTO.setTotalPeriod(projectBorrowerPlanNewDTO.getTotalPeriod());
		projectrePaymentResponseDTO.setRefundDate(projectBorrowerPlanNewDTO.getRefundDate());

		projectrePaymentResponseDTO.setCapital(projectBorrowerPlanNewDTO.getCapital());
		projectrePaymentResponseDTO.setInterest(projectBorrowerPlanNewDTO.getInterest());
		projectrePaymentResponseDTO.setPenaltyFee(projectBorrowerPlanNewDTO.getPenaltyFee());
		projectrePaymentResponseDTO.setManagementFee(projectBorrowerPlanNewDTO.getManagementFee());
		projectrePaymentResponseDTO.setGuaranteeFee(projectBorrowerPlanNewDTO.getGuaranteeFee());
		projectrePaymentResponseDTO.setRefundedCapital(projectBorrowerPlanNewDTO.getRefundedCapital());
		projectrePaymentResponseDTO.setRefundedInterest(projectBorrowerPlanNewDTO.getRefundedInterest());
		projectrePaymentResponseDTO.setRefundedPenaltyFee(projectBorrowerPlanNewDTO.getRefundedPenaltyFee());
		projectrePaymentResponseDTO.setRefundedManagementFee(projectBorrowerPlanNewDTO.getRefundedManagementFee());
		projectrePaymentResponseDTO.setRefundedGuaranteeFee(projectBorrowerPlanNewDTO.getRefundedGuaranteeFee());
		projectrePaymentResponseDTO.setRefundStatus(projectBorrowerPlanNewDTO.getStatus());
		projectrePaymentResponseDTO.setOverTime(projectBorrowerPlanNewDTO.getOverDate());
		projectrePaymentResponseDTO.setYearMouth(new DateTime(projectBorrowerPlanNewDTO.getRefundDate()).toString("yyyyMM"));
		projectrePaymentResponseDTO.setGenerateSource((byte) 0);
		projectrePaymentResponseDTO.setDelFlag((byte) 0);
		projectrePaymentResponseDTO.setCreateTime(projectBorrowerPlanNewDTO.getCreateTime());
		projectrePaymentResponseDTO.setUpdateTime(projectBorrowerPlanNewDTO.getUpdateTime());
		
		return projectrePaymentResponseDTO;
	} 
}